#include "StdAfx.h"
#include "ThreadSafeBuffer.h"
#include <iostream>
#include <sstream>
#include <cstdlib>

ThreadSafeBuffer::ThreadSafeBuffer( )
{ 
	IsClosed = true;
}

int ThreadSafeBuffer::Init(long lLengthOfBuffer , wstring strFileName)
{
	m_bSyncFlag = 0;
	hFile = CreateFile( strFileName.c_str(), GENERIC_WRITE, NULL , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL  , NULL );
	if( hFile == INVALID_HANDLE_VALUE )
	{
		return FILE_SYSTEM_WRITING_ERROR;
	}
	lBufferLength = lLengthOfBuffer;
	pBuffer = (char*)malloc( lBufferLength*sizeof(char) );
	if( pBuffer == 0 )
	{
		CloseHandle (hFile );
		hFile = INVALID_HANDLE_VALUE;
		return MEMORY_ALLOCATION_ERROR;
	}
	lBufferPointer = 0;
	IsClosed = false;
	return 0;
}
int ThreadSafeBuffer::Write( const wchar_t* strRecord , int nLen )
{
	int nCurrBufferLength = nLen;
	int nCurrBufferPointer = 0;
	long localBufferPointer;
	// Enter spinlock for working with iterator
	while ( InterlockedExchange( &m_bSyncFlag , 1 ) == 1 )
        Sleep(0);

	// If record can't be written by one time, write buffer to file
	while( nCurrBufferLength - nCurrBufferPointer >= lBufferLength - lBufferPointer )
	{
		// Full the buffer to the end
		for( long i = 0; i < lBufferLength - lBufferPointer; ++i)
		{
			pBuffer[ lBufferPointer + i ] = strRecord[ nCurrBufferPointer + i ];
		}
		nCurrBufferPointer += lBufferLength - lBufferPointer;

		// Send buffer to file, and clear for new record
		DWORD lWriten;
		WriteFile( hFile , pBuffer , lBufferLength*sizeof(char) , &lWriten , NULL );
		if( lWriten != lBufferLength*sizeof(char) )
		{
			CloseHandle( hFile );
			hFile = INVALID_HANDLE_VALUE;
			if( pBuffer != NULL)
				free( pBuffer );
			pBuffer = NULL;
			IsClosed = true;
			return FILE_SYSTEM_WRITING_ERROR;
		}
		lBufferPointer = 0;
	}

	// Exit spinlock
	InterlockedExchange( &m_bSyncFlag , 0 );

	localBufferPointer = InterlockedExchangeAdd( &lBufferPointer , nCurrBufferLength - nCurrBufferPointer );

	// copy all to buffer
	for(long i = 0; i < nCurrBufferLength - nCurrBufferPointer; ++i)
	{
		pBuffer[ localBufferPointer + i ] = strRecord[i + nCurrBufferPointer];
	}

	return 0;
}

int ThreadSafeBuffer::CloseFile()
{
	DWORD lWriten;
	WriteFile( hFile , pBuffer , lBufferPointer*sizeof(char) , &lWriten , NULL );
	if( lWriten != lBufferPointer*sizeof(char) )
	{
		CloseHandle( hFile );
		hFile = INVALID_HANDLE_VALUE;
		free( pBuffer );
		pBuffer = NULL;
		IsClosed = true;
		return FILE_SYSTEM_WRITING_ERROR;
	}
	CloseHandle( hFile );
	hFile = INVALID_HANDLE_VALUE;
	free( pBuffer );
	pBuffer = NULL;
	IsClosed = true;
	return 0;
}

ThreadSafeBuffer::~ThreadSafeBuffer(void)
{
	if( hFile != INVALID_HANDLE_VALUE )
		CloseHandle( hFile );
	if( pBuffer != NULL )
		free( pBuffer );
}

